<?php 
abstract class BaseApiController extends Yaf_Controller_Abstract {

	const RETURN_SUCCESS_CODE = '200';
	const RETURN_SUCCESS_MSG = 'success';


	protected $_error_msg = null;
	protected $_mysql_cluster = array();
	private $app_key = '';
	private $app_secret = '';
	public $app_key_array = array(
		'djinfu392j920m2xzc' => 'fdshfdvvw43s982afw47tyjybfb',
	);

	#不参与加密的字段
	protected $_not_encrypt_key = array('base64_string','ext_name');

	public function init(){
		Yaf_Dispatcher::getInstance()->autoRender(FALSE);
		$this->_error_msg = new System_ApiError();
		$this->_user_model = new UserModel();

		try{
//			#IOS base64 decode
//			$this->ios_base64_decode();
//
//			#检查基本参数
//			$this->check_required_params();
//
//			#检查app_key是否存在,是否正常访问
//			$this->check_appkey();

			#检查签名是否正确
			$params = $this->get_params();
//			if(!self::check_Sig($params, $this->app_secret)){
//				$code = 10020;
//				$msg = $this->_error_msg->system_errors[$code];
//				$this->echo_message($msg,$code);
//				exit;
//			}

			#检查api是否需要access_token,并且是否授权
			$this->check_access_token();
		}catch(Exception $ex){
			$code = 10001;
			$msg = $this->_error_msg->system_errors[$code];
			$this->echo_message($msg,$code);
			exit;
		}
	}


	#检查是否需要验证access_token
	private function check_access_token(){
		$params = $this->get_params();
		$controller_name = strtolower($this->getRequest()->controller);
		$action_name = $this->getRequest()->action;
		$this->request_api_is_require_logined = 0;

		#需要登录的接口
		if(in_array($controller_name, array( 'my', 'user', 'location'))) {
			$this->request_api_is_require_logined = 1;
		}

		if($this->request_api_is_require_logined == 1 && !isset($params['access_token']) && empty($params['access_token']) ){
			$code = 10022;
			$msg = $this->_error_msg->system_errors[$code];
			$this->echo_message($msg,$code);
			exit;
		}

		if($this->request_api_is_require_logined == 1){
			$access_token = trim($params['access_token']);

			try{
				@$access_token_obj = new AccessTokenModel();
				@$uid = (int)$access_token_obj->getUidbyAccessToken($access_token); //用token换UID
			}catch(Exception $ex){
				exit($ex->getMessage());
			}

			#用户的accesstoken是否失效
			if($uid == 0){
				$code = 10023; //			10023 => '已在其他设备登录，请重新登录',
				$msg = $this->_error_msg->system_errors[$code];
				$this->echo_message($msg,$code);
				exit;
			}

			$this->uid = $uid;
		}
	}


	#检查app_key
	private function check_appkey(){

		if(!isset($this->app_key_array[$this->app_key])) {
			$error_code = 10006;
			$error_msg = $this->_error_msg->system_errors[$error_code];
			$this->echo_message($error_msg, $error_code);
			exit;
		}

		$this->app_secret = $this->app_key_array[$this->app_key];
	}

	#get params
	private function get_params(){
		return $_REQUEST;
	}

	#sign
	private function generateSig($params, $secret = ''){
		$str = '';
		ksort($params);
		foreach ($params as $k => $v) {
			if(in_array($k,$this->_not_encrypt_key)){
				continue;
			}
			if (! is_array($v)) {
				$str .= "$k=$v";
			} else {
				ksort($v);
				$str .= "$k=" . json_encode($v);
			}
		}
		return hash_hmac('sha1', $str, $secret);
	}

	private function check_Sig($params, $secret = ''){
		$auth_signature = $params['auth_signature'];
		unset($params['auth_signature']);
		if($auth_signature == self::generateSig($params,$secret)){
			return true;
		}else{
			return false;
		}
	}

	#check the required params
	private function check_required_params(){
		$init_required_params = array(
			'app_key','auth_timestamp','auth_signature'
		);

		$request_params = $this->get_params();

		foreach ($init_required_params as $require_param) {
			if( !isset($request_params[$require_param]) ){
				$code = 10010;
				$msg = str_replace('(%s)', $require_param,$this->_error_msg->system_errors[$code]);
				$this->echo_message($msg,$code);
				exit;
			}
		}

		$this->app_key = trim($request_params['app_key']);
	}

	private function ios_base64_decode() {
		$ios_params = !empty($_REQUEST['ios_params']) ? $_REQUEST['ios_params'] : "";
		if(!empty($ios_params)) {
			$newstr = strtr($ios_params, '-_cexz', '+/#$%&');
			$newstr2 = strtr($newstr, '#$%&', 'eczx' );
			$newstr = strtr($newstr2, 'CEXZ', '#$%&');
			$newstr2 = strtr($newstr, '#$%&', 'ECZX' );
			$getjson = base64_decode($newstr2);
			if(!empty($getjson)) {
				$get_params = (array)json_decode($getjson);
				if(!empty($get_params)) {
					$_REQUEST = $get_params;
				}
			}
		}
	}
	/**
	 * 解密随机加密串中的规律数字
	 * @param time
	 * @return mixed
	 */
	protected function decryptString($time, $key){
		$w = intval(date('w',$time))+1;//1-7 星期
		$m = intval(date('m',$time));//1-12
		$d = intval(date('d',$time));//1-31
		$t = intval(date('s',$time));//0-60
		$str = $d . $t . $w . $m;  //日期 秒 星期 月份 数字拼接后，按照大小排序，16-此时数字的位数=随机数的位数
		$arr = preg_split("//", trim($str));
		sort($arr);
		$string = implode('', $arr);  //生成规律加密串
		//分解传过来的加密串
		$sort = substr($time , -1)%3;  //截取时间戳最后一位，对3取模
		$num = substr($key, 0, $sort).substr($key, $sort+9);

		if($string == $num){
			return 1;
		}else{
			return $time . '/' . $string.'/'.$num;
		}
	}


	/**
	 * 处理 params
	 * 进行ase解密，128位，测ecb模式
	 * @param string $params
	 * @param string $key
	 * @return mixed
	 */
	private function initParams($params, $key_value){
		$json = Aes::decryptNew($params, $key_value);
		if( empty($json) ) {
			$code = 10001;
			$msg = $this->_error_msg->system_errors[$code];
			$this->echo_message($msg, $code);
			exit;
		}

		$data = explode('&', $json);
		if( empty($data) ) {
			$code = 10001;
			$msg = $this->_error_msg->system_errors[$code];
			$this->echo_message($msg, $code);
			exit;
		}

		$get_params = array();
		foreach($data as $key => $value){
			$val = explode('=', $value);
			if(empty($val[0])){
				continue;
			}
			$get_params[$val[0]] = $val[1];
		}


		$check = $this->decryptString($get_params['auth_timestamp'], $key_value);
		$get_params['check'] = $check;

		if (!empty($get_params)) {
			$_REQUEST = $get_params;
		}

		return $_REQUEST;
	}


	#输出错误信息，默认是成功的
	public function echo_message($note = 'success',$num = 200,$info = array()){
		//替换错误
		if($num != self::RETURN_SUCCESS_CODE){
			$note = str_replace('_', ' ', $note);
			$note[0] = strtoupper($note[0]);
		}
		$return_data = array(
			'return_code' => strval($num),
			'return_msg' => $note,
			'return_data' => $info
		);
		echo json_encode($return_data);
		exit();
		#可以在此处调用api记录！！
	}

	private function brush_limit() {
		$brush_limit_model = new BrushLimitModel();
		$action_name = $this->getRequest()->action;
		$device_serial = isset($_REQUEST['device_serial']) ? addslashes(htmlspecialchars(trim($_REQUEST['device_serial']))) : '';
		$result = $brush_limit_model->visit($device_serial, $action_name);
		if(!$result) {
			$code = 25002;
			$msg = $this->_error_msg->system_errors[$code];
			$this->echo_message($msg,$code);
			exit;
		}
	}

	private function ip_brush_limit() {
		$brush_limit_model = new BrushLimitModel();
		$action_name = $this->getRequest()->action;
		$ip = $this->getIP();
		$result = $brush_limit_model->ip_visit($ip, $action_name);
		if(!$result) {
			$code = 25002;
			$msg = $this->_error_msg->system_errors[$code];
			$this->echo_message($msg,$code);
			exit;
		}
	}


	#写入日志
	function _log_result($str, $file_name = 'log.txt') {
		//目录
		$dir = "/data/bak/log/";
		#打开文件
		$fp = fopen($dir . $file_name,"a");
		#锁定，不允许其他人修改
		flock($fp, LOCK_EX) ;
		#写入
		fwrite($fp,"执行日期：".strftime("%Y%m%d%H%M%S",time()).": \n".$str."\n");
		#解锁
		flock($fp, LOCK_UN);
		#完毕
		fclose($fp);
	}

	#获取当前访问IP
	function getIp(){
		if (getenv('HTTP_CLIENT_IP')) {
			$now_ip = getenv('HTTP_CLIENT_IP');
		} elseif (getenv('HTTP_FORWARDED_FOR')) {
			$now_ip = getenv('HTTP_FORWARDED_FOR');
		} elseif (getenv('HTTP_X_FORWARDED')) {
			$now_ip = getenv('HTTP_X_FORWARDED');
		} elseif (getenv('HTTP_FORWARDED')) {
			$now_ip = getenv('HTTP_FORWARDED');
		} elseif (getenv('HTTP_X_FORWARDED_FOR')) {
			$now_ip = getenv('HTTP_X_FORWARDED_FOR');
		} else {
			$now_ip = $_SERVER['REMOTE_ADDR'];
		}
		return $now_ip;
	}

    protected function catchException($error_msg = ''){
    	if(empty($error_msg)){
    		return 10001;
    	}

    	#匹配error_code
    	preg_match('/(?<=error_code:-)[0-9]+/',$error_msg,$matches_code);

    	if(!empty($matches_code)){
    		return (int)$matches_code[0];
    	}else{
    		return 10001;
    	}
    }
    
    #记录API调用记录
	private function accessLog(){
		$ApiLogModel = new AccessLogModel();
		$mobile_idfa = isset($_REQUEST['device_serial']) ? addslashes(htmlspecialchars(trim($_REQUEST['device_serial']))) : '';
		$info = array(
			'remote_ip' => $this->getIP(),
			'request_uri' => addslashes(htmlspecialchars(trim(http_build_query($_REQUEST)))),
			'controllers' => addslashes(htmlspecialchars(trim($this->getRequest()->controller))),
			'action' => addslashes(htmlspecialchars(trim($this->getRequest()->action))),
			'module' =>  addslashes(htmlspecialchars(trim($this->getRequest()->action))),
			'deviceid' =>  $mobile_idfa,
			'time_created' => time()
		);
		$ret = $ApiLogModel->addData($info);
		if($ret){
			return true;
		}else{
			return false;
		}
	}


	/***
	 * @param string $url 链接
	 * @param int $code 错误码，默认是200，成功
	 * @param int $time_out 超时时间，默认是4秒
	 * @param array $header 头信息
	 * @return mixed 返回链接内容
	 * 获取远程链接
	 */
	public function curlGeURL($url = '', &$code = 200, $time_out = 4, $header = array()){
		if(empty($url)){
			return false;
		}
		#curl开始
		$ch = curl_init();
		curl_setopt($ch, CURLOPT_URL, $url);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
		curl_setopt($ch, CURLOPT_TIMEOUT, $time_out);
		curl_setopt($ch, CURLOPT_HEADER, 0);
		if(!empty($header)){
			curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
		}

		$output = curl_exec($ch);
		$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
		curl_close($ch);
		return $output;
	}


    function b64decode($string)
    {
        $url = str_replace(array('-', '_'), array('+', '/'), $string);
        $get_mod4 = strlen($url) % 4;
        if ($get_mod4) {
            $url .= substr('====', $get_mod4);
        }
        return base64_decode($url);
    }


    function decrypt($params, $keysercet)
    {
        $char_str = $string = '';
        $x = 0;
        $keysercet = md5($keysercet);
        $params = $this->b64decode($params);
        $len = strlen($params);
        $l = strlen($keysercet);
        for ($i = 0; $i < $len; $i++) {
            if ($x == $l) {
                $x = 0;
            }
            $char_str .= substr($keysercet, $x, 1);
            $x++;
        }
        for ($i = 0; $i < $len; $i++) {
            if (ord(substr($params, $i, 1)) < ord(substr($char_str, $i, 1))) {
                $string .= chr((ord(substr($params, $i, 1)) + 256) - ord(substr($char_str, $i, 1)));
            } else {
                $string .= chr(ord(substr($params, $i, 1)) - ord(substr($char_str, $i, 1)));
            }
        }
        return $string;
    }

}
